package com.sunreal.paygateway.Interceptors;

import java.lang.reflect.Method;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import com.alibaba.fastjson.JSON;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sunreal.paygateway.common.PayConstant;
import com.sunreal.paygateway.service.BaseService;
import com.sunreal.paygateway.sys.annotations.ResponseEncode;
import com.sunreal.paygateway.sys.annotations.ResponseSign;
import com.sunreal.paygateway.sys.util.GsonUtil;
import com.sunreal.paygateway.sys.util.PayDigestUtil;
import com.sunreal.paygateway.sys.util.result.RetResult;
import com.sunreal.paygateway.sys.util.result.WebResult;

/**
 * 功能描述：响应写出之前做一些处理。<p/>
 * 目前只是针对有注解{@link com.sunreal.paygateway.sys.annotations.ResponseSign @ResponseSign}的方法进行数据返回自动增加签名<br/>
 * 可以统一增加日志处理，记录每次被访问的方法以及返回值<br/>
 * 也可以对返回的数据进行统一加密，统一格式化返回结构等<br/>
 *
 * @Author 彭广
 * @Date 2019/4/16
 */
@Slf4j
@ControllerAdvice
public class LogResponseBodyAdvice implements ResponseBodyAdvice {
    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Autowired
    private BaseService baseService;

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        Method method = methodParameter.getMethod();
        String url = serverHttpRequest.getURI().toASCIIString();
        ResponseSign responseSign = methodParameter.getMethodAnnotation(ResponseSign.class);
        //如果有返回签名注解，并且为true，则对返回数据进行签名
        if (o instanceof WebResult) {
            RetResult retResult = new RetResult();
            WebResult webResult = (WebResult) o;
            String resKey = webResult.getResKey();
            //如果返回的是WebResult，则去掉resKey字段
            if (StringUtils.isBlank(webResult.getSign()) && StringUtils.isNotBlank(resKey)) {
                BeanUtils.copyProperties(webResult, retResult);
                o = retResult;
            }
            if (responseSign != null && responseSign.value()) {
                log.debug(method.getName() + "存在返回增加签名注解");
                try {
                    //返回参数增加签名
                    String sign = PayDigestUtil.getSign(retResult, resKey);
                    retResult.setSign(sign);
                    o = retResult;
                } catch (Exception e) {
                    log.error("返回参数签名失败！", e);
                    o = WebResult.retFail(e);
                }
            }
        }
        ResponseEncode responseEncode = methodParameter.getMethodAnnotation(ResponseEncode.class);
        //TODO 如果有返回加密注解，并且不为NULL，则对返回数据进行加密处理
        if (responseEncode != null && StringUtils.isNotBlank(responseEncode.value().name())) {
            log.debug(responseEncode.value().name());
        }
        //        log.debug("{}.{},url={},result={}", method.getDeclaringClass().getSimpleName(), method.getName(), url, GsonUtil.toJson(o));
        return o;
    }
}
